﻿
#include <memory>
#include <string>
#include <locale>
#include <codecvt>
#include <iostream>
#include <vector>
#include <map>
#include <set>
using namespace std;

// 这些是种子和语法糖文件
#include "../hpp/0-Seed.h"
#include "../hpp/1-Sugar.h"

// 这些是 nVoid 标准库
#include "../hpp/nOS/FileSys.h"
#include "../hpp/nMath/Base.h"
using namespace nVoid;

// 没有实现 itClass 的类不能融入 nVoid 框架
class tXVec
{
public:
};

// 实现 itClass 的类可以融入 nVoid 框架
class tVec : public itClass
{
public:

	double x, y;

	explicit tVec(double a_x = 0, double a_y = 0)
		: x(a_x), y(a_y)
	{ }

	double cLen() const { return sqrt(this->x * this->x + this->y * this->y); }

	tStr operator ()(tStr const& a_P = "**", tStr const& a_S = "**")
	{
		return tStr::scCat(a_P, " tVec as Functor ", a_S);
	}

protected:

	//------------------------- 必须实现的接口

	virtual ptClass vdVoid_Copy(ptClass const& a_pThis) const
	{
		return ptClass(new tVec(this->x, this->y));
	}

	virtual tStr vdVoid_ToStr() const
	{
		return tStr::scCat("tVec(", this->x, ", ", this->y, ")");
	}

	virtual tStr vdVoid_ToJson(int a_Indent = 0) const
	{
		return tStr::scCat("[", this->x, ", ", this->y, "]");
	}

	//------------------------- 可选实现的接口

	//若注释掉，会产生异常：Type Error: Cast <tVec> to <bool>
	virtual bool vdVoid_ToBool() const
	{
		return this->x != 0 || this->y != 0;
	}

	virtual tVar vdVoid_Op1(tStr const& a_Op)
	{
		if (a_Op == "-_") { return tVar(tVec(-this->x, -this->y)); }

		return itClass::vdVoid_Op1(a_Op);
	}

	virtual tVar vdVoid_Call(tStr const& a_M, tTup const& a_Args)
	{
		if (a_M == "()") { return tVar(this->operator()(a_Args.cGet(0, "**"), a_Args.cGet(1, "**"))); }
		if (a_M == "cLen") { return tVar(this->cLen()); }

		return itClass::vdVoid_Call(a_M, a_Args);
	}
};

void fTest_Base()
{
	tStr s1("abc"), s2("xyz");
	s1 = s2; s2 = 'S';
	cout << tStr::scCat() << endl;
	cout << tStr::scCat(true, 23, "456") << endl;
	cout << tStr::scCatSep(", ") << endl;
	cout << tStr::scCatSep(", ", true, 23, "456") << endl;
	s1 = "abc//def//xyz";
	s2 = "//abc//def//";
	cout << s1.cSplit("//").cLen() << " = " << tStr::scJoin(", ", s1.cSplit("//")) << endl;
	cout << s2.cSplit("//").cLen() << " = " << tStr::scJoin(", ", s2.cSplit("//")) << endl;
	cout << tStr::scJoin("//", s2.cSplit("//")).cLen() << " = " << tStr::scJoin("//", s2.cSplit("//")) << endl;
	cout << endl;

	s1 = " \tabc\frst\vxyz\r\n";
	cout << s1.cTrim(0) << "|" << s1.cTrim(0).cLen() << endl;
	cout << s1.cTrim(1) << "|" << s1.cTrim(0).cLen() << endl;
	cout << s1.cTrim() << "|" << s1.cTrim(0).cLen() << endl;

	cout << tStr::scHexOf((unsigned short)256) << ", " << tStr::scHexOf((unsigned short)65535) << endl; // 0100, ffff
	cout << tStr::scHexTo("FFFFFFFF") << endl; // 4294967295

	cout << tStr("a我b").cEncodeUnicodeEscape() << endl;
	cout << tStr("a我b").cEncodeUnicodeEscape().cDecodeUnicodeEscape() << endl;

	cout << endl << "-------------------------" << endl << endl;
}

void fTest_BuiltIn()
{
	// 定义变量、字典、元组
	var x = 3; cout << x << endl; assert(x == 3); // 3
	x = "xyz"; cout << x << endl; assert(x == "xyz"); // xyz
	x = true; cout << x << endl; assert(x == true); // true
	x = nullptr; cout << x << endl; // null 【不推荐】
	x = null; cout << x << endl; assert(x == null); // null 【推荐】
	cout << endl;
	
	dic m(
		key("Name") = "Mike",
		key("Age") = 33,
		key("Married") = false,
		key("Wife") = null,
		key("Likes") = tup("Reading", "Swimming", 123.456),
		key("Edus") = tup
		(
			dic(
				key("College") = "Stanford",
				key("Degree") = "Master",
			etc),
			dic(
				key("College") = "MIT",
				key("Degree") = "Bachelor",
			etc),
			"...",
		etc),
	etc);


	dic mm = m; // 深拷贝
	mm["Name"] = "xyz"; assert(mm["Name"] == "xyz"); assert(mm["Name"] != m["Name"]);
	cout << "mm.Name = " << mm["Name"] << ", m.Name = " << m["Name"] << endl;

	tup aa(null, true, 123, 456.789, "xyz");
	tup bb = aa; // 深拷贝
	aa[2] = 1230; assert(aa[2] == 1230); assert(bb[2] != aa[2]);
	cout << "aa[2] = " << aa[2] << ", bb[2] = " << bb[2] << endl;
	bb[2] = aa[2]; assert(bb[2] == aa[2]);
	cout << "aa[2] = " << aa[2] << ", bb[2] = " << bb[2] << endl;
	//the raa2(aa[2]); //【报错】
	//tRefToTup raa3(aa[3]); //【报错】
	cout << "<tRef> == <tRefToTup>: " << (mm["Name"] == aa[4]) << endl; assert(mm["Name"] == aa[4]);
	cout << endl;

	// 测试引用 和 null
	the rn(m["Wife"]); // 这是引用
	rn = "Sarah"; assert("Sarah" == m["Wife"]);
	cout << m["Wife"] << endl; // "Sarah"
	rn = null; assert(m["Wife"] == null);
	cout << m["Wife"] << endl; // null
	cout << endl;

	// 测试 tRef 和 tVar 的转换
	m["Job"] = "C++ Programmer"; 
	cout << m["Job"] << endl; // C++ Programmer
	var v = m["Job"]; assert(v == "C++ Programmer");
	cout << v << endl; // C++ Programmer
	v = 123; assert(v == 123);
	cout << v << endl; // 123
	cout << m["Job"] << endl; // C++ Programmer
	assert(m["Job"] == "C++ Programmer");
	
	// 测试动态类型
	var u;
	cout << u << endl; // null
	u = "u is a string."; assert(u == "u is a string.");
	cout << u << endl; // u is a string.
	u = v;  assert(123 == u);
	cout << u << endl; // 123
	u = m; assert(u == m);
	cout << "u = " << (int)u << ", m.cLen() = " << m.cLen() << endl; // 7
	u = null; assert(u.cIsNull());
	cout << endl;

	// 测试算术
	the ra(m["Age"]); // 这是引用
	u = ra; assert(u == 33);
	cout << u << endl; // 33
	u += 1; assert(u == 34); assert(ra == 33);
	cout << ra << endl; // 33
	cout << u << endl; // 34
	ra += 1; assert(ra == 34);
	cout << ra << endl; // 34
	cout << u + 10 << endl; // 44
	cout << 20 + u << endl; // 54
	cout << u + ra << endl; // 68
	cout << ra + u << endl; // 68
	ra += ra; assert(m["Age"] == 68); // 68
	ra += u; assert(m["Age"] == 102);// 68 + 34 = 102
	cout << m["Age"] << endl; // 102
	cout << m["Age"] + 3 << endl; // 105
	cout << 5 + m["Age"] << endl; // 107
	cout << endl;

	// 测试 tDic 的增删改查
	cout << m["AnyType"] << endl; // null
	m["AnyType"] = 123; assert(m["AnyType"] == 123);
	cout << m["AnyType"] << endl; // 123
	m["AnyType"] = "abc"; assert(m["AnyType"] == "abc");
	cout << m["AnyType"] << endl; // "abc"
	m["AnyType"] = null; // 仍然会留在 m 中
	cout << m.cHas("AnyType") << endl; assert(m.cHas("AnyType") == true); // 1
	m.cErase("AnyType"); // 不在 m 中
	cout << m.cHas("AnyType") << endl; assert(m.cHas("AnyType") == false); // 0
	cout << endl;

	// 测试tDic::cGet()
	cout << m.cGet("Get", 999) << endl; assert(m.cGet("Get", 999) == 999); // 999
	cout << m.cGet("Age") << endl; assert(m.cGet("Age") == 102); // 102
	cout << endl;

	// 测试元组
	var likes = m["Likes"];
	cout << likes[2].cTypename() << endl; assert(likes[2].cTypename() == "float"); // float
	likes[2] = "Learning Math";
	cout << likes[2].cTypename() << endl; assert(likes[2].cTypename() == "tStr"); // tStr
	likes.cSort();
	likes[0] += " and Physics"; // 改变元组元素
	cout << likes << endl; assert(likes[0] == "Learning Math and Physics"); assert(likes[0] != m["Likes"][0]);
	cout << m["Likes"] << endl; // 元组的元素变了，但元素的顺序没变
	m["Likes"] = likes; assert(m["Likes"][0] == "Learning Math and Physics"); // 元组变了
	// ... 待进一步测试
	cout << endl;

	// 这样直接引用是可以的
	tDic& r(m["Edus"][0]);
	r["Degree"] += " and Doctor";
	cout << r << endl; assert(m["Edus"][0]["Degree"] == "Master and Doctor");
	cout << endl;

	// 无符号类型支持
	m["UnsignedLongLong"] = 0xFFFFFFFFFFFFFFFF;// ‭18,446,744,073,709,551,615‬
	assert(m["UnsignedLongLong"] == 18446744073709551615);

	// 转成JSON
	cout << aa.cToJson() << endl;
	cout << bb.cToJson() << endl;
	cout << m.cToJson() << endl;
	cout << endl;

	// 解析JSON
	tStr errs;
	var json;
	if (!fParseJsonFromFile(errs, json, "./test/person.json")) { cout << errs << endl; }
	else { cout << json.cToJson() << endl; }
	cout << endl;
	assert(json == m);

	// 如果 u 不是 tTup，引发异常
	try
	{
		u.cSort();
	}
	catch (exception const& o_Exc)
	{
		cout << "[EXC]: " << o_Exc.what() << endl;
	}

	cout << endl << "-------------------------" << endl << endl;

}

void fTest_Fun()
{
	// 测试调用方法
	auto o_fCA = fun(prms(key("a_Add") = 0, key("a_Sub") = 1), // 默认总是 + 0 - 1 
		[](tDic& a_This, tDic const& a_Args) -> var {
			cout << "a_Args[a_Add] = " << a_Args["a_Add"] << ", a_Args[a_Sub] = " << a_Args["a_Sub"] << endl;
			a_This["c_Age"] += a_Args["a_Add"];
			a_This["c_Age"] -= a_Args["a_Sub"];
			return null;
		}
	);

	dic obj(
		key("c_Age") = 29,
		key("cGetAge") = fun([](tDic& a_This, tDic const& a_Args) -> var { return a_This["c_Age"]; }),
		key("cChangeAge") = o_fCA,
	etc);

	cout << obj["cGetAge"]() << endl; assert(obj["cGetAge"]() == 29); // 29
	//obj["cChangeAge"](2, 3); // 29 + 2 - 3
	obj.it(cChangeAge)(2, 3); 
	cout << obj.it(c_Age) << endl; assert(obj["cGetAge"]() == 28); // 28
	the ca(obj["cChangeAge"]), ga(obj["cGetAge"]);
	ca(key("a_Add") = 7); assert(obj["cGetAge"]() == 34); // 28 + 7 - 1 = 34 【具名参数、默认参数】
	cout << ga() << endl; // 34
	ca(key("a_Add") = 8, key("a_Sub") = 2); assert(obj["cGetAge"]() == 40); // 34 + 8 - 2 = 40 【具名参数】
	cout << ga() << endl; // 40
	cout << ga.cToJson() << endl; // "<tFun: ?>"

	cout << endl << "-------------------------" << endl << endl;
}

void fTest_Class()
{
//	tXVec XV; var xv = XV; // C2027: 使用了未定义类型“nVoid::tVal<tXVec>”

	tVec V1(3, 4), V2(6, 8);
	var v1 = V1; // OK
	cout << "v1 Type = " << v1.cTypename() << ", RealType = " << v1.cRealTypename() << endl; assert(v1.cTypename() == "itClass" && v1.cRealTypename() == "tVec");
	cout << "v1 = " << v1 << endl;  // tVec(3, 4)
	cout << "-v1 = " << -v1 << endl; assert((-v1).cInst<tVec>().x == -3 && (-v1).cInst<tVec>().y == -4); // tVec(-3, -4)
	cout << "v1.cLen() = " << v1.cCall("cLen") << endl; assert(nMath::fAbs(v1.cCall("cLen") - 5.0) < 0.00001); // 5
	cout << v1("--", "==") << endl; // -- tVec as Functor ==
	cout << v1("--") << endl;       // -- tVec as Functor **
	cout << v1() << endl;           // ** tVec as Functor **
	cout << v1.cCall("()", "++", "##") << endl; assert(tStr(v1.cCall("()", "++", "##")) == "++ tVec as Functor ##"); // ++ tVec as Functor ##
	cout << "v1 is 0 vec ? -- " << (v1 ? "no" : "yes") << endl; // cast to <bool>

	cout << endl << "-------------------------" << endl << endl;
}

void fTest_StdLib()
{
	var v1 = -16;
	cout << nMath::fAbs(v1) << endl; assert(nMath::fAbs(v1) == 16);
	cout << nMath::fSqrt(-v1) << endl; assert(nMath::fSqrt(-v1) == 4);
	cout << nMath::fPow(v1, 2) << endl; assert(nMath::fPow(v1, 2) == 256);

	cout << endl << "-------------------------" << endl << endl;
}


int main()
{
	try
	{
		//fTest_Base();
		fTest_BuiltIn();
		fTest_Fun();
		fTest_Class();
		fTest_StdLib();
	}
	catch (exception const& o_Exc)
	{
		cout << "[EXC]: " << o_Exc.what() << endl;
	}

	//cin.get();
	return 0;
}